//////////////////////////////////////////////////////////////////////////
//
// Vector Graph Core2D
//
// Module:
//        Matrix2D.cs
//
// Description:
//        Implementation of basic operation of 3*3 affine matrix
//
// Author:
//        Created on 2008.04.14 by Destrayer
//
//////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Drawing2D;

namespace VectorGraph.Core2D
{
    class Matrix2D
    {
        protected double[] m = new double[6];

        public Matrix2D()
            : this(1, 0, 0, 1, 0, 0)
        {
        }

        public Matrix2D(double m11, double m12, double m21, double m22, double dx, double dy)
        {
            this.m[0] = m11;
            this.m[1] = m12;
            this.m[2] = m21;
            this.m[3] = m22;
            this.m[4] = dx;
            this.m[5] = dy;
        }

        public Matrix ToAffineMatrix()
        {
            return new Matrix((float)this.m[0], (float)this.m[1], (float)this.m[2], (float)this.m[3], (float)this.m[4], (float)this.m[5]);
        }

        public void Reset()
        {
            this.m[0] = 1;
            this.m[1] = 0;
            this.m[2] = 0;
            this.m[3] = 1;
            this.m[4] = 0;
            this.m[5] = 0;
        }

        public void Multiply(Matrix2D matrix)
        {
            double[] b = matrix.m;
            this.Multiply(b[0], b[1], b[2], b[3], b[4], b[5]);
        }

        public void Multiply(double m11, double m12, double m21, double m22, double dx, double dy)
        {
            double a11 = this.m[0];
            double a12 = this.m[1];
            double a21 = this.m[2];
            double a22 = this.m[3];
            double a31 = this.m[4];
            double a32 = this.m[5];

            this.m[0] = a11 * m11 + a12 * m21;
            this.m[1] = a11 * m12 + a12 * m22;
            this.m[2] = a21 * m11 + a22 * m21;
            this.m[3] = a21 * m12 + a22 * m22;
            this.m[4] = a31 * m11 + a32 * m21 + dx;
            this.m[5] = a31 * m12 + a32 * m22 + dy;
        }

        public void Translate(double dx, double dy)
        {
            this.m[4] += dx;
            this.m[5] += dy;
        }

        public void Rotate(double cosAngle, double sinAngle)
        {
            this.Multiply(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
        }

        public void Scale(double scale)
        {
            this.Scale(scale, scale);
        }

        public void Scale(double scaleX, double scaleY)
        {
            this.m[0] *= scaleX;
            this.m[1] *= scaleY;
            this.m[2] *= scaleX;
            this.m[3] *= scaleY;
            this.m[4] *= scaleX;
            this.m[5] *= scaleY;
        }

        public double ScaleRateX()
        {
            return Math.Sqrt(this.m[0] * this.m[0] + this.m[1] * this.m[1]);
        }

        public double ScaleRateY()
        {
            return Math.Sqrt(this.m[2] * this.m[2] + this.m[3] * this.m[3]);
        }

        protected void TransformPoint(ref Point2d pt)
        {
            double x = pt.X;
            pt.X = x * this.m[0] + pt.Y * this.m[2] + this.m[4];
            pt.Y = x * this.m[1] + pt.Y * this.m[3] + this.m[5];
        }

        protected void TransformPoints(Point2d[] pts)
        {
            for (int i = 0; i < pts.Length; i++)
            {
                this.TransformPoint(ref pts[i]);
            }
        }

        protected void InverseTransformPoint(ref Point2d pt)
        {
            double d1 = pt.X - this.m[4];
            double d2 = pt.X - this.m[5];
            double c = this.m[0] * this.m[3] - this.m[1] * this.m[2];
            pt.X = (d1 * this.m[3] - d2 * this.m[2]) / c;
            pt.Y = (d2 * this.m[0] - d1 * this.m[1]) / c;
        }

        protected void InverseTransformPoints(Point2d[] pts)
        {
            for (int i = 0; i < pts.Length; i++)
            {
                this.InverseTransformPoint(ref pts[i]);
            }
        }
    }
}
